<?php
/**
 * Recommendation class, responsible for calculating/retrieving the suggestions for given artist and track
 */
class Recommendation{
    private $database;
    /**
     * Constructor
     */
    public function Recommendation(){
        $this->database=new Database();
    }

    /* Returns a list of the best artists for a given artist and optionally a user.
     * If no user is logged in, the list of scores from NewSuggestions is sorted and returned.
     * If a user is logged in, the list will be sorted to fit his genre-preferences best.
    */
    public function getTopArtists($idArtist, $idUser){
        $artistList=array();
        $query='SELECT DISTINCT NewSuggestions.id2 FROM NewSuggestions WHERE NewSuggestions.id='.$idArtist.' ORDER BY NewSuggestions.score DESC';
        $result=mysql_query($query);
        while($row = mysql_fetch_array($result)){
            array_push($artistList,$this->database->getArtistByID($row[0], false,false,0,0));
        }
        $newList = array();
        $iterator = 0;
        
        // FOR EVERY USER: 
               
        foreach($artistList as $a)
        {
            
            $newList[$iterator] = array();
            $newList[$iterator]['artist'] = $a;
            $score = 0;
            $query='SELECT NewSuggestions.score FROM NewSuggestions WHERE NewSuggestions.id='.$idArtist.' AND NewSuggestions.id2='.$a->id();
            $result=mysql_query($query);
            if($row = mysql_fetch_array($result))
            {
                if($row['score'] != 0)
                {
                    $score = $row['score'];
                }
            }
            $newList[$iterator]['score'] = $score;
            $iterator++;
        }
        
        // IF NOT LOGGED IN:
        
        if($idUser == null || $idUser <= 0)
        {
            $returnList = array();
            $length = count($newList);
            for($i = 0; $i < $length; $i++)
            {
                $max = 0;
                $artist = null;
                $index = 0;
                for($j = 0; $j < count($newList); $j++)
                {
                    if($newList[$j]['score'] > $max)
                    {
                        $max = $newList[$j]['score'];
                        $artist = $newList[$j]['artist'];
                        $index = $j;
                    }
                }
                if($artist!=null)
                    array_push($returnList, $artist);
                $newList[$index] = null;
            }
            return $returnList;
        }
        
        // IF LOGGED IN:
        // Determine his appreciation of every genre as a number in (0,1)
        $query = 'SELECT idGenre, count, rating FROM NewUserGenre WHERE idUser = '.$idUser;
        $result=mysql_query($query);
        $userGenre = array();
        $max = 0;
        while($row=mysql_fetch_array($result))
        {
            $normalised = $row['count']*($row['rating']-1)/4;
            $userGenre[$row['idGenre']] = $normalised;
            if($normalised > $max)
                $max = $normalised;
        }
        foreach($userGenre as $id=>$genre){
            $userGenre[$id] /= $max;
        }
        $iterator = 0;
        
        // For all artists, determine his correlation and multiply it with the former
        // score to get the new score
        foreach($artistList as $a)
        {
            $correlation = 0;
            $count = 0;
            $query = 'SELECT Genre1ID, Genre2ID, Genre3ID FROM NewArtistGenre, NewArtist WHERE NewArtist.id = '.$a->getID().' AND NewArtist.id = NewArtistGenre.ArtistID';
            $result = mysql_query($query);
            while($row=mysql_fetch_array($result))
            {
                for($i = 1; $i < 4; $i++)
                {
                    if(isset($userGenre[$row['Genre'.$i.'ID']]))
                    {
                        $correlation += $userGenre[$row['Genre'.$i.'ID']];
                        $count++;
                    }
                }
            }
            if($count > 0)
                $correlation /= $count;
            
            $newList[$iterator]['score']*=$correlation;
            $iterator++;
        }
        //Sort and return
        $returnList = array();
        $length = count($newList);
        for($i = 0; $i < $length; $i++)
        {
            $max = 0;
            $artist = null;
            $index = 0;
            for($j = 0; $j < count($newList); $j++)
            {
                if($newList[$j] != null && $newList[$j]['score'] > $max)
                {
                    $max = $newList[$j]['score'];
                    $artist = $newList[$j]['artist'];
                    $index = $j;
                }
            }
            if($artist!=null)
                array_push($returnList, $artist);
            $newList[$index] = null;
        }
        return $returnList;
    }
    
    public function getList($idArtist,$limitAlbums=2,$limitTracks=2){
        //get [limitAlbums] albums where the sum of the rating is the highest, get [limitTracks] tracks of those albums orderd on rating
        $query='select id as idTrack,idAlbum
                from
                (
                        select id,NewTrack.idAlbum,sum(listened)*(sum(rating)/count(distinct rating)-1)/4 as ratingTrack,NewTrack.name
                        from (NewTrack,NewUserTrack) INNER JOIN
                        (
                                select NewAlbum.id as idAlbum, sum(listened)*(sum(rating)/count(distinct rating)-1)/4 as ratingAlbum
                                from NewUserTrack
                                join NewTrack on NewTrack.id=NewUserTrack.idTrack
                                join NewAlbum on NewAlbum.id=NewTrack.idAlbum
                                where NewAlbum.idArtist="'.$idArtist.'"
                                group by NewAlbum.id
                                order by ratingAlbum desc
                                limit '.$limitAlbums.'
                        ) temp
                        ON temp.idAlbum=NewTrack.idAlbum
                        where NewUserTrack.idTrack=NewTrack.id
                        group by NewUserTrack.idTrack
                        order by ratingTrack desc
                        
                ) as temp2
                order by idAlbum';
       
        $result=mysql_query($query);
        $return=array();
        $currentAlbum=-1;
        $album=null;
        while($row=  mysql_fetch_array($result)){
            if($currentAlbum==-1||$currentAlbum!=$row['idAlbum']){
                if($album!=null){
                array_push($return,$album);
                }
                $album=$this->database->getAlbumByID($row['idAlbum'],0);

                $currentAlbum=$row['idAlbum'];
            }
            $album->addTrack($this->database->getTrackByID($row['idTrack'],false));     
        }
        if($album!=null){
            array_push($return,$album);
        }
        return $return;
    }
    /* Processing a rating means adapting the suggestions to fit the new averages.
     * This is done in two steps; decide the correlation of this user with this artist 
     * based on his liking of this artist's genres and then updating all scores of
     * this artist for other artists. 
    */
    public function processRating($rating, $trackID)
    {
        //First, get the score for all genres of 'user'.
        $id = $this->database->getCache('user');
        $query = 'SELECT idGenre, count, rating FROM NewUserGenre WHERE idUser = '.$id;
        $result=mysql_query($query);
        $userGenre = array();
        $max = 0;
        while($row=mysql_fetch_array($result))
        {
            $normalised = $row['count']*($row['rating']-1)/4;
            $userGenre[$row['idGenre']] = $normalised;
            if($normalised > $max)
                $max = $normalised;
        }
        foreach($userGenre as $id=>$genre) {
            $userGenre[$id] /= $max;
        }
        
        //Then determine the correlation between the artist and user
        $correlation = 0;
        $count = 0;
        $query = 'SELECT Genre1ID, Genre2ID, Genre3ID, ArtistID FROM NewArtistGenre, NewArtist, NewAlbum, NewTrack WHERE NewTrack.id = '.$trackID.' AND NewAlbum.id = NewTrack.idAlbum AND NewArtist.id = NewAlbum.idArtist AND NewArtist.id = NewArtistGenre.ArtistID';
        $result = mysql_query($query);
        $artistID;
        while($row=mysql_fetch_array($result))
        {
            $artistID = $row['ArtistID'];
            for($i = 0; $i < 3; $i++)
            {
                if($userGenre[$row['Genre'.($i+1).'ID']])
                {
                    $correlation += $userGenre[$row['Genre'.($i+1).'ID']];
                    $count++;
                }
            }
        }
        if($count > 0)
            $correlation /= $count;
        
        //The adapted rating is defined as a number between -1 and 1
        $adaptedRating = ($rating-3)/2;
        
        //Now get all artist for whom the rated artist is suggested
        $querySuggestions = 'SELECT DISTINCT ID, score, refScore FROM NewSuggestions WHERE ID2 = '.$artistID;
        $resultSuggestions = mysql_query($querySuggestions);
        
        //For all these artists:
        while($rowSuggestions = mysql_fetch_array($resultSuggestions))
        {
            // Get all relevant values
            $score = $rowSuggestions['score'];
            $refScore = $rowSuggestions['refScore'];
            $id = $rowSuggestions['ID'];
            
            // Now to get the variables neccessary for the score-update
            $scoreUpdate = 'SELECT COUNT(NewUserTrack.rating) AS ratings, SUM(NewUserTrack.rating) AS sumRatings FROM NewArtist,NewAlbum,NewTrack,NewUserTrack WHERE NewArtist.id='.$artistID.' AND NewAlbum.idArtist=NewArtist.id AND NewAlbum.id=NewTrack.idAlbum AND NewUserTrack.idTrack=NewTrack.id';
            $resultScoreUpdate = mysql_query($scoreUpdate);
            $ratingCount = 0;
            $totalRating = 0;
            if($rowScoreUpdate = mysql_fetch_array($resultScoreUpdate))
            {
                //Total
                $ratingCount = $rowScoreUpdate['ratings'];
                //Total*Average
                $totalRating = $rowScoreUpdate['sumRatings'];
            }
            
            // The adapted total rating is the sum of adapated averages
            $adaptedTotalRating = ($totalRating - 3*$ratingCount)/2;
            // And the normalized averaged is the average of adapted averages
            $normalizedAverage = ($adaptedTotalRating + $adaptedRating*$correlation)/($ratingCount+1);
            
            //Maximum deviation from initial: 100
            $newScore = $refScore + $normalizedAverage*100;
            mysql_query('UPDATE NewSuggestions SET score='.$newScore.' WHERE ID = '.$id.' AND ID2 = '.$artistID);
        }
    }
}
